﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Hyldahl.Services.TaskProcessing.FibonacciCalculation
{
    public class FibonacciCalculationTaskProcessor : TaskProcessor
    {
        /*****************************************************
         * METHODS
         *****************************************************/

        #region TaskProcessor Members

        /// <summary>
        /// Processes the specified task.
        /// </summary>
        /// <param name="task">The task.</param>
        public override void Process(Task task)
        {
            if (task == null)
                throw new ArgumentNullException("task");

            if (string.Compare(task.TaskType, this.TaskType, true) != 0)
                throw new ArgumentException("Invalid task type.");

            int fibonacci = 0;

            if(string.IsNullOrEmpty(task.Data))
                throw new ArgumentException("No task data.", "task");

            if (!int.TryParse(task.Data, out fibonacci))
                throw new ArgumentException("Invalid task data. Could not parse number.", "task");

            if(fibonacci < 0)
                throw new ArgumentException("Invalid task data. Number cannot be negative.", "task");

            task.ResultData = CalculateFibonacci(fibonacci).ToString();

            task.IsProcessed            = true;
            task.CompletedSuccessfully  = true;
        }

        /// <summary>
        /// Calculates fibonacci numbers.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <returns></returns>
        public int CalculateFibonacci(int x)
        {
            /*
                F(n) = F(n-1) + F(n-2)
                where F(1) = F(2) = 1, F(0) = 0
             
                F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17  F18  F19  F20 
                0  1  1  2  3  5  8  13 21 34 55  89  144 233 377 610 987 1597 2584 4181 6765 
             */

            if (x == 0)
                return 0;

            if (x == 1 || x == 2)
                return 1;

            int previous    = -1;
            int result      = 1;

            for (int idx = 0; idx <= x; ++idx)
            {
                int sum = result + previous;

                previous    = result;
                result      = sum;
            }

            return result;
        }

        /*****************************************************
         * PROPERTIES
         *****************************************************/

        /// <summary>
        /// Gets the type of the supported task.
        /// </summary>
        /// <value>The type of the supported task.</value>
        public override string TaskType
        {
            get { return "Fibonacci"; }
        }

        #endregion
    }
}
